﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Baddies.Utils;

namespace BaddiesEditor
{
    public partial class EditorForm : Form
    {
        /// <summary>
        /// Reference to the last added tile to the tilePanel, for dynamic
        /// positioning of new tiles.
        /// </summary>
        private PictureBox lastAddedTile;

        /// <summary>
        /// Margin to be observed when adding a new tile to the tilePanel.
        /// </summary>
        private int tileMargin = 2;

        /// <summary>
        /// Bitmap with the current loaded tileset.
        /// </summary>
        private Bitmap tileset;

        /// <summary>
        /// Size of the tile in pixels. Tiles are square, so W = H = tileSize.
        /// </summary>
        private int tileSize;

        /// <summary>
        /// Reference to the game running in the PictureBox.
        /// </summary>
        private EditorGame game;

        /// <summary>
        /// Sets the reference to the game.
        /// </summary>
        /// <value>Game to reference.</value>
        public EditorGame Game
        {
            set { this.game = value; }
        }

        /// <summary>
        /// Information needed to change the icon of the cursor.
        /// </summary>
        public struct IconInfo
        {
            public bool fIcon;
            public int xHotspot;
            public int yHotspot;
            public IntPtr hbmMask;
            public IntPtr hbmColor;
        }

        /// <summary>
        /// Initializes a new instance of the EditorForm class.
        /// </summary>
        public EditorForm()
        {
            InitializeComponent();
            this.lastAddedTile = null;
            this.tileset = null;
            this.tileSize = 16;
        }

        public IntPtr getDrawSurface()
        {
            return gameViewport.Handle;
        }

        private void EditorForm_Load(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// Invoked when a tile is clicked in the editor.
        /// </summary>
        /// <param name="sender">Class that sends the msg.</param>
        /// <param name="e">TileClickArg arguments.</param>
        private void TileClicked(object sender, EventArgs e)
        {
            Bitmap bmp = ((TileClickArg)e).TileBmp;
            this.gameViewport.Cursor = CreateCursor(bmp, 0, 0);
        }

        #region LoadTiles
        private void AddTile(Bitmap bitmap, Point tilemapCoords)
        {
            TilePictureBox pic = new TilePictureBox(tilemapCoords, this.TileClicked);            
            pic.Size = new Size(tileSize, tileSize);
            pic.Image = bitmap; 
            tilePanel.Controls.Add(pic);

            // Position it
            if (this.lastAddedTile == null)
            {
                // If there is no "Last added tile" we're the first, 
                // so go to the initial location.
                pic.Location = new Point(tileMargin, tileMargin);
            }
            else
            {
                // Get the space left to the left of the last added 
                int curLeftMargin = this.lastAddedTile.Location.X + this.lastAddedTile.Size.Width;
                int maxLeftMargin = this.tilePanel.Size.Width;
                int remainingSpace = maxLeftMargin - curLeftMargin;

                // See if we fit in there
                if (remainingSpace >= pic.Size.Width + this.tileMargin)
                {
                    // If we fit, get in there!
                    pic.Location = new Point(curLeftMargin + this.tileMargin, this.lastAddedTile.Location.Y);
                }
                else
                {
                    // If we don't, jump to the next line
                    pic.Location = new Point(this.tileMargin, this.lastAddedTile.Location.Y + this.tileMargin + tileSize);
                }
            }
            this.lastAddedTile = pic;
        }

        private void LoadTilesFromTileMap(Bitmap tileMap)
        {
            this.tileset = tileMap;
            this.tilePanel.Controls.Clear();
            this.lastAddedTile = null;

            for (int x = 0; x < this.tileset.Size.Width; x += this.tileSize)
            {
                for (int y = 0; y < this.tileset.Size.Height; y += this.tileSize)
                {
                    Rectangle cropArea = new Rectangle(x, y, this.tileSize, this.tileSize);
                    Bitmap tileImg = this.tileset.Clone(cropArea, this.tileset.PixelFormat);
                    this.AddTile(tileImg, new Point(x,y));
                }
            }
        }

        private void loadNewTilesetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog dlg = new OpenFileDialog())
            {
                dlg.Title = "Open Image";
                dlg.Filter = "image files (*.png)|*.png";

                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    Bitmap newTileSet = new Bitmap(dlg.FileName);
                    this.LoadTilesFromTileMap(newTileSet);
                }
            }
        }
        #endregion // LoadTiles

        #region ChangeCursor
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);

        [DllImport("user32.dll")]
        public static extern IntPtr CreateIconIndirect(ref IconInfo icon);

        public static Cursor CreateCursor(Bitmap bmp, int xHotSpot, int yHotSpot)
        {
            IntPtr ptr = bmp.GetHicon();
            IconInfo tmp = new IconInfo();
            GetIconInfo(ptr, ref tmp);
            tmp.xHotspot = xHotSpot;
            tmp.yHotspot = yHotSpot;
            tmp.fIcon = false;
            ptr = CreateIconIndirect(ref tmp);
            return new Cursor(ptr);
        }

        public Cursor GetDefaultCursor()
        {
            return Cursors.Arrow;
        }
        #endregion // ChangeCursor

        #region NewMap
        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NewMap newMap = new NewMap(NewMapOkHandler);
            newMap.Show();
        }

        public void NewMapOkHandler(object sender, EventArgs e)
        { 
            NewMapConfirmArg arg = (NewMapConfirmArg)e;
            this.game.NewMap(arg.Width, arg.Height, arg.TileSize);
        }


        #endregion // NewMap

    }
}
